package com.aerfafish.spider.graph;

import com.aerfafish.spider.callback.SpiderCallback;
import com.aerfafish.spider.constant.CacheConstant;
import com.aerfafish.spider.constant.SpiderConfig;
import com.aerfafish.spider.neo4j.dao.*;
import com.aerfafish.spider.neo4j.spider.service.*;
import com.aerfafish.spider.redis.CacheStorage;
import com.aerfafish.spider.spider.CompanySpider;
import com.aerfafish.spider.spider.FundSpider;
import com.aerfafish.spider.spider.ManagerSpider;
import com.aerfafish.spider.spider.ShareSpider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @author aerfafish
 * @date 2021/4/23 2:43 下午
 */
@Component
public class GraphUpdater {

    private final static Logger logger = LoggerFactory.getLogger(GraphUpdater.class);

    @Autowired
    ShareService shareService;

    @Autowired
    PersonFundRelationService personFundService;

    @Autowired
    FundShareRelationService fundShareService;

    @Autowired
    FundService fundService;

    @Autowired
    PersonService personService;

    @Autowired
    FundDateRelationService fundDateService;

    @Autowired
    CompanyService companyService;

    @Autowired
    PersonCompanyRelationService personCompanyService;

    @Autowired
    CompanyShareRelationService companyShareService;

    @Autowired
    CompanyFundRelationService companyFundService;

    @Autowired
    FundEstablishService fundEstablishService;

    @Autowired
    CacheStorage cacheStorage;

    SpiderCallback spiderCallback;

    FundSpider fundSpider;

    CompanySpider companySpider;

    ManagerSpider managerSpider;

    ShareSpider shareSpider;

    @PostConstruct
    public void init() {

        spiderCallback = new SpiderCallback() {
            @Override
            public void onSaveFund(Fund fund) {
                try {
                    fundService.save(fund);
                    for (int i = 0; true; i++) {
                        if (cacheStorage.set(CacheConstant.getUpdateFundKey(fund.getCode())
                                , System.currentTimeMillis(), SpiderConfig.cacheTime)) {
                            break;
                        } else if (i == 3) {
                            logger.error("update fund: " + fund.getCode() + " error");
                            return;
                        }
                    }
                } catch (Exception e) {
                    logger.error("", e);
                } finally {
                    cacheStorage.releaseLock(CacheConstant.getUpdateFundLock(fund.getCode()));
                }
            }

            @Override
            public void onSaveCompany(Company company) {
                try {
                    companyService.save(company);
                    for (int i = 0; true; i++) {
                        if (cacheStorage.set(CacheConstant.getUpdateCompanyKey(company.getCode())
                                , System.currentTimeMillis(), SpiderConfig.cacheTime)) {
                            break;
                        } else if (i == 3) {
                            logger.error("update company: " + company.getCode() + " error");
                            return;
                        }
                    }
                } catch (Exception e) {
                    logger.error("", e);
                } finally {
                    cacheStorage.releaseLock(CacheConstant.getUpdateCompanyLock(company.getCode()));
                }
            }

            @Override
            public void onSaveShare(Share share) {
                try {
                    shareService.save(share);
                    for (int i = 0; true; i++) {
                        if (cacheStorage.set(CacheConstant.getUpdateShareKey(share.getMarket()+share.getCode())
                                , System.currentTimeMillis(), SpiderConfig.cacheTime)) {
                            break;
                        } else if (i == 3) {
                            logger.error("update share: " + share.getCode() + " error");
                            return;
                        }
                    }
                } catch (Exception e) {
                    logger.error("", e);
                } finally {
                    cacheStorage.releaseLock(CacheConstant.getUpdateShareLock(share.getMarket()+share.getCode()));
                }
            }

            @Override
            public void onSavePerson(Person person) {
                try {
                    personService.save(person);
                    for (int i = 0; true; i++) {
                        if (cacheStorage.set(CacheConstant.getUpdatePersonKey(person.getCode())
                                , System.currentTimeMillis(), SpiderConfig.cacheTime)) {
                            break;
                        } else if (i == 3) {
                            logger.error("update person: " + person.getCode() + " error");
                            return;
                        }
                    }
                } catch (Exception e) {
                    logger.error("", e);
                } finally {
                    cacheStorage.releaseLock(CacheConstant.getUpdatePersonLock(person.getCode()));
                }
            }

            @Override
            public void onSaveFundShareRelation(FundHoldShare fundHoldShare, String fundCode, String shareCode) {
                try {
                    updateFund(fundCode);
                    if (shareCode == null || shareCode.equals("")) {
                        logger.error("fundCode = " + fundCode + " shareCode null");
                    }
                    updateShare(shareCode);
                    fundShareService.save(fundHoldShare, fundCode, shareCode);

                } catch (Exception e) {
                    logger.error("", e);
                }
            }

            @Override
            public void onSaveFundDateRelation(FundValue fundValue, String fundCode, String date) {
                try {
                    fundDateService.save(fundValue, fundCode, date);
                } catch (Exception e) {
                    logger.error("", e);
                }
            }

            @Override
            public void onSavePersonFundRelation(String personCode, String fundCode) {
                try {
                    updatePerson(personCode);
                    updateFund(fundCode);
                    personFundService.save(personCode, fundCode);

                } catch (Exception e) {
                    logger.error("", e);
                }
            }

            @Override
            public void onSavePersonCompanyRelation(String personCode, String companyCode) {
                try {
                    updatePerson(personCode);
                    updateCompany(companyCode);
                    personCompanyService.save(personCode, companyCode);
                } catch (Exception e) {
                    logger.error("", e);
                }
            }

            @Override
            public void onSaveCompanyShareRelation(CompanyHoldShare companyHoldShare, String companyCode, String shareCode) {
                if (companyCode == null || shareCode == null) {
                    return;
                }
                try {
                    updateCompany(companyCode);
                    updateShare(shareCode);
                    companyShareService.save(companyHoldShare, companyCode, shareCode);

                } catch (Exception e) {
                    logger.error("", e);
                }
            }

            @Override
            public void onSaveCompanyFundRelation(String companyCode, String fundCode) {
                try {
                    updateCompany(companyCode);
                    updateFund(fundCode);
                    companyFundService.save(companyCode, fundCode);

                } catch (Exception e) {
                    logger.error("", e);
                }
            }

            @Override
            public void onSaveFundEstablishDate(String fundCode, String date) {
                try {
                    updateFund(fundCode);
                    fundEstablishService.save(fundCode, date);
                } catch (Exception e) {
                    logger.error("", e);
                }
            }
        };

        fundSpider = new FundSpider(spiderCallback);
        companySpider = new CompanySpider(spiderCallback);
        managerSpider = new ManagerSpider(spiderCallback);
        shareSpider = new ShareSpider(spiderCallback);

    }

    // 一次更新所有数据 因为更新数据是多线程，所以更新某一个数据时需要对该数据上锁。防止通过其他关系同时更新该数据
    public void update() {}

    // 检查当前key是否存在，若不存在则加锁。并且爬取该基金信息，然后检查基金的管理人 管理公司 持股 key是否存在，若不存在则同样加锁爬取信息。
    public void updateFund(String fundCode) {
        String fundUpdateTime = null;
        Object fundUpdateTimeObject = cacheStorage.get(CacheConstant.getUpdateFundKey(fundCode));
        if (fundUpdateTimeObject != null) {
            fundUpdateTime = fundUpdateTimeObject.toString();
        }
        if (fundUpdateTime != null && System.currentTimeMillis() - Long.parseLong(fundUpdateTime) < SpiderConfig.updateTime) {
            return;
        }
        if (!cacheStorage.acquireLock(CacheConstant.getUpdateFundLock(fundCode), "LOCK", SpiderConfig.lockTime)) {
            return;
        }
        fundSpider.spiderFund(fundCode);
    }

    public void updatePerson(String personCode) {
        String personUpdateTime = null;
        Object personUpdateTimeObject = cacheStorage.get(CacheConstant.getUpdatePersonKey(personCode));
        if (personUpdateTimeObject != null) {
            personUpdateTime = personUpdateTimeObject.toString();
        }
        if (personUpdateTime != null && System.currentTimeMillis() - Long.parseLong(personUpdateTime) < SpiderConfig.updateTime) {
            return;
        }
        if (!cacheStorage.acquireLock(CacheConstant.getUpdatePersonLock(personCode), "LOCK", SpiderConfig.lockTime)) {
            return;
        }
        managerSpider.spiderManager(personCode);
    }

    public void updateShare(String shareCode) {
        String shareUpdateTime = null;
        Object shareUpdateTimeObject = cacheStorage.get(CacheConstant.getUpdateShareKey(shareCode));
        if (shareUpdateTimeObject != null) {
            shareUpdateTime = shareUpdateTimeObject.toString();
        }
        if (shareUpdateTime != null && System.currentTimeMillis() - Long.parseLong(shareUpdateTime) < SpiderConfig.updateTime) {
            return;
        }
        if (!cacheStorage.acquireLock(CacheConstant.getUpdateShareLock(shareCode), "LOCK", SpiderConfig.lockTime)) {
            return;
        }

        shareSpider.spiderShare(shareCode);
    }

    public void updateCompany(String companyCode) {
        String companyUpdateTime = null;
        Object companyUpdateTimeObject = cacheStorage.get(CacheConstant.getUpdateCompanyKey(companyCode));
        if (companyUpdateTimeObject != null) {
            companyUpdateTime = companyUpdateTimeObject.toString();
        }
        if (companyUpdateTime != null && System.currentTimeMillis() - Long.parseLong(companyUpdateTime) < SpiderConfig.updateTime) {
            return;
        }
        if (!cacheStorage.acquireLock(CacheConstant.getUpdateCompanyLock(companyCode), "LOCK", SpiderConfig.lockTime)) {
            return;
        }
        companySpider.spiderCompany(companyCode);
    }

}
